package cn.huoyingkeji.common.domain;

import java.io.Serializable;

import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.servlet.http.HttpServletResponse;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

@Getter
@Setter
@ToString
public class R<T> implements Serializable {
    @Schema(description = "响应码")
    private int code;

    @Schema(description = "错误码")
    private int failCode;

    @Schema(description = "响应消息")
    private String message;

    @Schema(description = "成功标志")
    private boolean success = true;

    @Schema(description = "时间戳")
    private long timestamp = System.currentTimeMillis();

    private T data;

    private R(IResultCode resultCode) {
        this(resultCode, null, resultCode.getMessage());
    }

    private R(IResultCode resultCode, String message) {
        this(resultCode, null, message);
    }

    private R(IResultCode resultCode, T data) {
        this(resultCode, data, resultCode.getMessage());
    }

    private R(IResultCode resultCode, T data, String message) {
        this(resultCode.getCode(), data, message);
    }
    private R(int code, T data, String message) {
        this.code = code;
        this.data = data;
        this.message = message;
        this.success = ResultCode.SUCCESS.getCode() == code;
    }

    private R(int code,int failCode, T data, String message) {
        this.code = code;
        this.data = data;
        this.failCode = failCode;
        this.message = message;
        this.success = ResultCode.SUCCESS.getCode() == code;
    }

    /**
     * 返回R
     *
     * @param data 数据
     * @param <T>  T 泛型标记
     * @return R
     */
    public static <T> R<T> data(T data) {
        return data(data, "操作成功！");
    }

    /**
     * 返回R
     *
     * @param data 数据
     * @param message  消息
     * @param <T>  T 泛型标记
     * @return R
     */
    public static <T> R<T> data(T data, String message) {
        return data(HttpServletResponse.SC_OK, data, message);
    }

    /**
     * 返回R
     *
     * @param code 状态码
     * @param data 数据
     * @param message  消息
     * @param <T>  T 泛型标记
     * @return R
     */
    public static <T> R<T> data(int code, T data, String message) {
        return new R<>(code, data, data == null ?  "操作成功": message);
    }

    /**
     * 返回R
     *
     * @param message 消息
     * @param <T> T 泛型标记
     * @return R
     */
    public static <T> R<T> success(String message) {
        return new R<>(ResultCode.SUCCESS, message);
    }

    /**
     * 返回R
     *
     * @param resultCode 业务代码
     * @param <T>        T 泛型标记
     * @return R
     */
    public static <T> R<T> success(IResultCode resultCode) {
        return new R<>(resultCode);
    }

    /**
     * 返回R
     *
     * @param resultCode 业务代码
     * @param message        消息
     * @param <T>        T 泛型标记
     * @return R
     */
    public static <T> R<T> success(IResultCode resultCode, String message) {
        return new R<>(resultCode, message);
    }

    /**
     * 返回R
     *
     * @param message 消息
     * @param <T> T 泛型标记
     * @return R
     */
    public static <T> R<T> fail(String message) {
        return new R<>(ResultCode.FAILURE, message);
    }


    /**
     * 返回R
     *
     * @param code 状态码
     * @param message  消息
     * @param <T>  T 泛型标记
     * @return R
     */
    public static <T> R<T> fail(int code, String message) {
        return new R<>(code, null, message);
    }

    /**
     * 返回R
     *
     * @param resultCode 业务代码
     * @param <T>        T 泛型标记
     * @return R
     */
    public static <T> R<T> fail(IResultCode resultCode) {
        return new R<>(resultCode);
    }

    /**
     * 返回R
     *
     * @param resultCode 业务代码
     * @param message        消息
     * @param <T>        T 泛型标记
     * @return R
     */
    public static <T> R<T> fail(IResultCode resultCode, String message) {
        return new R<>(resultCode, message);
    }

    /**
     * 返回R
     *
     * @param flag 成功状态
     * @return R
     */
    public static <T> R<T> status(boolean flag) {
        return flag ? success("操作成功") : fail("操作失败");
    }
}
